package pl.ppsoft.fixlang;

import pl.ppsoft.fixlang.common.HandleEvent;
import pl.ppsoft.fixlang.common.Utils;
import pl.ppsoft.fixlang.dto.RestLessonDTO;
import pl.ppsoft.fixlang.dto.RestLessonsResponseDTO;
import pl.ppsoft.fixlang.dto.RestResponseDTO;
import pl.ppsoft.fixlang.dto.RestWordDTO;
import pl.ppsoft.fixlang.dto.RestWordsResponseDTO;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

import com.google.gson.reflect.TypeToken;

public class SyncLessonsTask extends AsyncTask<Void, Integer, Integer> {
	private Activity activity;
	private ProgressDialog progressDialog;
	private String exception;
	private String url;
	private DbAdapter db;
	private HandleEvent handler;
	
	public SyncLessonsTask(Activity activity, DbAdapter db, String url, HandleEvent handler) {
		this.activity = activity;
		this.url = url;
		this.db = db;
		this.handler = handler;
	}

	@Override
	protected void onPreExecute() {
		progressDialog = new ProgressDialog(activity);
		progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
		progressDialog.setMessage( activity.getString( R.string.sync_progress ) );
		progressDialog.show();
	}

	protected void onProgressUpdate(Integer... progress) {
		progressDialog.incrementProgressBy(progress[0]);
    }
	
	protected Integer doInBackground(Void ... urls) {
		publishProgress(0);
        try {
        	RestLessonsResponseDTO response =  Utils.postREST( url + "/synclessons", db.restSyncLessons(), new TypeToken<RestLessonsResponseDTO>(){}.getType() );        	
        	if ( response.isOk() ) {        	
        		int size = response.getL().size();
        		if ( size > 0 ) {
	        		int step = 80/size;        			
		        	for (RestLessonDTO lesson : response.getL()) {
						switch (lesson.getS()) {
						case DbAdapter.LESSON_STATUS_DELETED:
							db.deleteRestLesson(lesson.getI());
							break;
						case DbAdapter.LESSON_STATUS_MODIFIED:
							db.updateRestLesson(lesson.getI(), lesson.getN(), lesson.getT());
							break;
						case DbAdapter.LESSON_STATUS_OK:
							db.updateRestLessonStatus(lesson.getI(), DbAdapter.LESSON_STATUS_OK);
							break;
						case DbAdapter.LESSON_STATUS_NEW:
							db.beginTransaction();
							try {
								long lessonId = db.addRestLesson(lesson);
								this.syncWords(lessonId, lesson.getR());
								db.setTransactionSuccessful();
							} finally {
								db.endTransaction();
							}
							break;
						case DbAdapter.LESSON_STATUS_SYNC_NEW_WORDS:
							db.beginTransaction();
							try {					
								db.updateRestLessonServerId(lesson.getI(), lesson.getR());
								this.syncWords(lesson.getI(), lesson.getR());
								db.updateRestLessonStatus(lesson.getI(), DbAdapter.LESSON_STATUS_OK);
								db.setTransactionSuccessful();
							} finally {
								db.endTransaction();
							}						
							break;
						case DbAdapter.LESSON_STATUS_SYNC_MODIFIED_WORDS:
							db.beginTransaction();
							try {					
								db.updateRestLessonWordStamp(lesson.getI(), lesson.getW());
								this.syncWords(lesson.getI(), lesson.getR());
								db.updateRestLessonStatus(lesson.getI(), DbAdapter.LESSON_STATUS_OK);
								db.setTransactionSuccessful();
							} finally {
								db.endTransaction();
							}						
							break;
						case DbAdapter.LESSON_STATUS_SYNC_NEW_ARCHIVE:
							db.beginTransaction();
							try {					
								db.updateRestLessonServerId(lesson.getI(), lesson.getR());
								this.syncArchiveWords(lesson.getI(), lesson.getR());
								db.deleteRestWords(lesson.getI());
								db.updateRestLessonStatus(lesson.getI(), DbAdapter.LESSON_STATUS_ARCHIVED);
								db.setTransactionSuccessful();
							} finally {
								db.endTransaction();
							}						
							break;
						case DbAdapter.LESSON_STATUS_SYNC_MODIFIED_ARCHIVE:
							db.beginTransaction();
							try {					
								db.updateRestLessonWordStamp(lesson.getI(), lesson.getW());
								this.syncArchiveWords(lesson.getI(), lesson.getR());
								db.deleteRestWords(lesson.getI());
								db.updateRestLessonStatus(lesson.getI(), DbAdapter.LESSON_STATUS_ARCHIVED);
								db.setTransactionSuccessful();
							} finally {
								db.endTransaction();
							}						
							break;
						case DbAdapter.LESSON_STATUS_SYNC_ARCHIVE_OK:
							db.doLessonArchive(lesson.getI());
							break;
						}
						
		        		publishProgress(step);					
		        	}
        		}
	        	
	        	publishProgress(100);
        	} else {
        		throw new Exception( response.getErr() );
        	}
        	
        } catch(Exception e) {
        	exception = e.getLocalizedMessage();
        	Log.e("runJSONParser", "Error parsing JSON", e);
            e.printStackTrace();
        }

		return null;
    }

	private void syncWords(long lessonId, long serverId) throws Exception {    		    		
		RestWordsResponseDTO response =  Utils.postREST( url + "/syncwords/" + serverId, db.restSyncWords(lessonId), new TypeToken<RestWordsResponseDTO>(){}.getType() );

		if ( response.isOk() ) { 
	    	for (RestWordDTO word : response.getL()) {
				switch (word.getS()) {
				case DbAdapter.WORD_STATUS_DELETED:
					db.deleteRestWord(word.getI());
					break;
				case DbAdapter.WORD_STATUS_MODIFIED:
					db.updateRestWord(word.getI(), word.getQ(), word.getA(), word.getE(), word.getT());
					break;
				case DbAdapter.WORD_STATUS_OK:
					db.updateRestWordStatus(word.getI(), word.getR(), DbAdapter.WORD_STATUS_OK);
					break;
				case DbAdapter.WORD_STATUS_NEW:
					db.addRestWord(word, lessonId);
					break;
				}
			}
		} else {
			throw new Exception( response.getErr() );
		}
    }

	private void syncArchiveWords(long lessonId, long serverId) throws Exception {    		    		
    	RestResponseDTO response =  Utils.postREST( url + "/syncarchwords/" + serverId, db.restSyncWords(lessonId), new TypeToken<RestResponseDTO>(){}.getType() );
    	if ( !response.isOk() ) {
			throw new Exception( response.getErr() );    		
    	}
    }

	@Override
	protected void onPostExecute(Integer result) {
    	handler.doEvent();

    	progressDialog.dismiss();
    	if ( exception != null ) {
    		AlertDialog.Builder alertbox = new AlertDialog.Builder(activity);
            alertbox.setMessage("ERROR: " + exception);
            alertbox.setNeutralButton(R.string.btn_ok, null );                    
            alertbox.show();        		
    	} else {
    		Toast.makeText(activity, activity.getString( R.string.sync_success ), Toast.LENGTH_LONG).show();        		
    	}
    }        
}
